package white440.controller;


import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.GridLayout;
import java.awt.KeyEventDispatcher;
import java.awt.KeyboardFocusManager;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.net.InetAddress;
import java.net.MalformedURLException;
import java.net.UnknownHostException;
import java.rmi.Naming;
import java.rmi.NotBoundException;
import java.rmi.Remote;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.rmi.server.UnicastRemoteObject;

import javax.swing.DefaultDesktopManager;
import javax.swing.JButton;
import javax.swing.JDesktopPane;
import javax.swing.JFrame;
import javax.swing.JInternalFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.UIManager;

import white440.common.RemoteController;
import white440.common.RemoteTruck;

import com.sun.media.ui.MessageBox;

public class TruckGui extends UnicastRemoteObject implements RemoteController{


	/*************************************************************************
	 * MAIN PROGRAM / STATIC METHODS
	 *************************************************************************/

	public static void main(String args[]) {
		try {
			new TruckGui();
		} catch (RemoteException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	static void Fatal(String s) {

		new MessageBox("Warning",s);
	}    

	/*************************************************************************
	 * VARIABLES
	 *************************************************************************/
	/**
	 * 
	 */
	private static final long serialVersionUID = 2835276640650913200L;

	JFrame frame;
	//JMFrame jmframe = null;
	JDesktopPane desktop;

	//Player player = null;
	//Player newPlayer = null;
	String filename;

	private RemoteTruck truck;
	private int currentThrottle;
	private int throttleIncrement = 20;
	private int currentDirection;
	private int directionIncrement = 90/5;
	JTextArea messages = new JTextArea("System Messages: \n");

	//Add Menu Bar
	JMenuBar menuBar;
	JMenu file;
	JMenuItem mInstructions, mExit;

	/*************************************************************************
	 * METHODS
	 * @throws RemoteException 
	 *************************************************************************/

	public TruckGui() throws RemoteException {
		super();
		frame = new JFrame("Truck Control");

		//TODO rmi
		try {//register this with the local rmi registry
			Registry reg = LocateRegistry.getRegistry();
			reg.rebind(RemoteController.RMINAME, this);
			System.out.println("Controller bound to: rmi://"
					+ InetAddress.getLocalHost().getHostAddress()
					+ "/" + RemoteController.RMINAME);
		} catch (RemoteException e1) {
			// TODO Auto-generated catch block
			e1.printStackTrace();
		} catch (UnknownHostException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}	
		String ip = JOptionPane.showInputDialog("Input IP Address of the truck.");
		if(ip != null){
			String loc = "rmi://"+ip+"/"+RemoteTruck.RMINAME;
			System.out.println("Connecting to truck at: " + loc);
			try {
				Remote obj = Naming.lookup(loc);
				if(obj instanceof RemoteTruck){
					truck = (RemoteTruck) obj;
					truck.setController(this);
					System.out.println("Connected to truck!");					
				}else{
					System.out.println("truck is not a RemoteTruck");
				}
			} catch (MalformedURLException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (RemoteException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (NotBoundException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		// Add the desktop pane
		desktop = new JDesktopPane();
		//desktop.setDoubleBuffered(true);
		desktop.setBackground(Color.black);
		//GridLayout layout = new GridLayout(1,2);
		//desktop.setLayout(layout);
		desktop.setPreferredSize(new Dimension(800,280));
		desktop.setDragMode(JDesktopPane.LIVE_DRAG_MODE);
		desktop.setDesktopManager(new DefaultDesktopManager());
		JScrollPane scrollPane = new JScrollPane(desktop);

		frame.setLayout(new BorderLayout());
		frame.add(scrollPane,BorderLayout.CENTER);
		frame.add( createControls(),BorderLayout.SOUTH);

		//Add menuBar
		menuBar = new JMenuBar();
		file = new JMenu("File");
		menuBar.add(file);

		mInstructions = new JMenuItem("System Controls");
		mInstructions.addActionListener(new ActionListener(){

			@Override
			public void actionPerformed(ActionEvent e) {
				// TODO Auto-generated method stub
				JOptionPane.showMessageDialog(frame, 
						"Throttle Control:" +
						"\n The throttle has 10 different settings. 5 forward and 5 reverse settings. " +
						"\n The throttle can be increased or decreased by one increment at a time by" +
						"\n pressing the up or down arrow keys or by using the buttons (Faster/Slower)." +
						"\n Throttle can be returned to zero by pressing ctrl + up arrow or ctrl + down arrow keys" +
						"\n or it can be returned to zero by pressing the Zero Throttle button" +
						"\n " +
						"\n Steering Control:" +
						"\n The steering has 10 different seetings. 5 left and 5 right settings. " +
						"\n The steering can be adjusted right or left by one increment at a time by pressing" +
						"\n the left or right keys on the keyboard or by using the buttons (Left/Right)." +
						"\n Steering can be returned to zero by pressing ctrl + left or ctrl + right arrow keys" +
				"\n or it can be zeroed by pressing the Zero Steering button");
			}
		});

		mExit = new JMenuItem("Exit");
		mExit.addActionListener(new ActionListener(){

			@Override
			public void actionPerformed(ActionEvent arg0) {
				// TODO Auto-generated method stub
				System.exit(0);
			}
		});

		file.add(mInstructions);
		file.add(mExit);
		frame.add(menuBar, BorderLayout.NORTH);

		if(truck.isConnected()){
			startVideoDisplay();
		}

		startKeyboardControl();

		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		frame.pack();
		frame.setVisible(true);	

		try {
			UIManager.setLookAndFeel("javax.swing.plaf.metal.MetalLookAndFeel");
		} catch (Exception e) {
			System.err.println("Could not initialize java.awt Metal lnf");
		}
		frame.addWindowListener( new WindowAdapter() {
			public void windowClosing(WindowEvent we) {
				System.exit(0);
			}
		} );
	}



	private void startKeyboardControl() {
		KeyboardFocusManager.getCurrentKeyboardFocusManager().addKeyEventDispatcher(new KeyEventDispatcher(){

			@Override
			public boolean dispatchKeyEvent(KeyEvent arg0) {
				if(arg0.getID() == KeyEvent.KEY_PRESSED){
					System.out.print(arg0.getKeyCode());
					switch(arg0.getKeyCode()){
					//				case KeyEvent.VK_CONTROL:
					//					zeroNext = true;
					//					break;
					case KeyEvent.VK_UP:
						//check if this will set to zero
						if(arg0.getModifiers() == KeyEvent.CTRL_MASK){
							try {
								boolean isSet = truck.setThrottle(0);
								if(isSet){
									currentThrottle = 0;
								}else{
									//TODO display message
								}
							} catch (RemoteException e) {
								// TODO check if connected and disp message
								e.printStackTrace();
							}
						}else{
							if((currentThrottle + throttleIncrement) <= 100){//in range
								try {
									boolean isSet = truck.setThrottle(currentThrottle + throttleIncrement);
									if(isSet){
										currentThrottle = currentThrottle + throttleIncrement;
									}else{
										//TODO display message
									}
								} catch (RemoteException e) {
									// TODO display message on gui
									e.printStackTrace();
								}
							}else{
								messages.append("At full throttle");
							}
						}
						//zeroNext = false;
						break;
					case KeyEvent.VK_DOWN:
						//check if this will set to zero
						if(arg0.getModifiers() == KeyEvent.CTRL_MASK){
							try {
								boolean isSet = truck.setThrottle(0);
								if(isSet){
									currentThrottle = 0;
								}else{
									//TODO display message
								}
							} catch (RemoteException e) {
								// TODO check if connected and disp message
								e.printStackTrace();
							}
						}else{
							if((currentThrottle - throttleIncrement) >= -100){//in range
								try {
									boolean isSet = truck.setThrottle(currentThrottle - throttleIncrement);
									if(isSet){
										currentThrottle = currentThrottle - throttleIncrement;
									}else{
										//TODO display message
									}
								} catch (RemoteException e) {
									// TODO display message on gui
									e.printStackTrace();
								}
							}else{
								//TODO display error
								messages.append("At max reverse");
							}
						}
						//zeroNext = false;
						break;
					case KeyEvent.VK_LEFT:
						if(arg0.getModifiers() == KeyEvent.CTRL_MASK){
							try {
								boolean isSet = truck.setDireciton(0);
								if(isSet){
									currentDirection = 0;
								}else{
									//TODO disp message
								}
							} catch (RemoteException e) {
								// TODO disp message
								e.printStackTrace();
							}
						}else{
							if(currentDirection - directionIncrement >= -90){
								try {
									boolean isSet = truck.setDireciton(currentDirection - directionIncrement);
									if(isSet){
										currentDirection = currentDirection - directionIncrement;
									}else{
										//TODO disp message
									}
								} catch (RemoteException e) {
									// TODO display message
									e.printStackTrace();
								}
							}else{
								//TODO Display message
								messages.append("At max left angle");
							}
						}
						//zeroNext = false;
						break;
					case KeyEvent.VK_RIGHT:
						if(arg0.getModifiers() == KeyEvent.CTRL_MASK){
							try {
								boolean isSet = truck.setDireciton(0);
								if(isSet){
									currentDirection = 0;
								}else{
									//TODO disp message
								}
							} catch (RemoteException e) {
								// TODO disp message
								e.printStackTrace();
							}
						}else{
							if(currentDirection + directionIncrement <= 90){
								try {
									boolean isSet = truck.setDireciton(currentDirection + directionIncrement);
									if(isSet){
										currentDirection = currentDirection + directionIncrement;
									}else{
										//TODO disp message
									}
								} catch (RemoteException e) {
									// TODO display message
									e.printStackTrace();
								}
							}else{
								//TODO display message
								messages.append("At max right angle");
							}
						}
						//zeroNext = false;
						break;
					}
				}
				return false;
			}

		});
	}

	private void startVideoDisplay(){
		for (int i = 0; i < 2; i++) {//add camera components
			JInternalFrame inFrame = new JInternalFrame("Camera Feed "+i,true,true,true,true);
			inFrame.add(new WebcamComponent(i, truck));
			inFrame.setSize(new Dimension(400,280));
			inFrame.setLocation(400*i, 0);
			inFrame.setResizable(true);
			inFrame.setDefaultCloseOperation(JInternalFrame.DO_NOTHING_ON_CLOSE);
			desktop.add(inFrame);
			inFrame.setVisible(true);
		}	
	}

	private JPanel createControls(){

		JPanel Control = new JPanel();
		Control.setSize(500, 500);
		Control.setLayout(new GridLayout(1,2));

		final JTextArea messages = new JTextArea("System Messages: \n");
		messages.setEditable(false);
		JScrollPane scrollMsg = new JScrollPane(messages);
		messages.setCaretPosition( messages.getDocument().getLength() );
		Control.add(scrollMsg);

		JPanel controls = new JPanel();
		Control.add(controls);
		controls.setLayout(new GridLayout(2,3));

		JButton zeroSteer = new JButton("Zero Steering");
		controls.add(zeroSteer);

		JButton faster = new JButton("Faster");
		controls.add(faster);

		JButton zeroThrottle = new JButton("Zero Throttle");
		controls.add(zeroThrottle);

		JButton leftSteer = new JButton("Left");
		controls.add(leftSteer);

		JButton slower = new JButton("Slower");
		controls.add(slower);

		JButton rightSteer = new JButton("Right");
		controls.add(rightSteer);

		ActionListener aListener = new ActionListener() {
			public void actionPerformed(ActionEvent ae) {
				String command = ae.getActionCommand();

				if (command.equals("Left")) {  
					if(currentDirection - directionIncrement >= -90){
						try {
							boolean isSet = truck.setDireciton(currentDirection - directionIncrement);
							if(isSet){
								currentDirection = currentDirection - directionIncrement;
							}else{
								//TODO disp message
							}
						} catch (RemoteException e) {
							// TODO display message
							e.printStackTrace();
						}
					}else{
						//TODO Display message
						messages.append("At max left angle");
					}
				}

				else if (command.equals("Right")){
					if(currentDirection + directionIncrement <= 90){
						try {
							boolean isSet = truck.setDireciton(currentDirection + directionIncrement);
							if(isSet){
								currentDirection = currentDirection + directionIncrement;
							}else{
								//TODO disp message
							}
						} catch (RemoteException e) {
							// TODO display message
							e.printStackTrace();
						}
					}else{
						//TODO display message
						messages.append("At max right angle");
					}
				}

				else if (command.equals("Faster")){
					if((currentThrottle + throttleIncrement) <= 100){//in range
						try {
							boolean isSet = truck.setThrottle(currentThrottle + throttleIncrement);
							if(isSet){
								currentThrottle = currentThrottle + throttleIncrement;
							}else{
								//TODO display message
							}
						} catch (RemoteException e) {
							// TODO display message on gui
							e.printStackTrace();
						}
					}else{
						//TODO display error
						messages.append("At full throttle");
					}
				}

				else if (command.equals("Slower")){
					if((currentThrottle - throttleIncrement) >= -100){//in range
						try {
							boolean isSet = truck.setThrottle(currentThrottle - throttleIncrement);
							if(isSet){
								currentThrottle = currentThrottle - throttleIncrement;
							}else{
								//TODO display message
							}
						} catch (RemoteException e) {
							// TODO display message on gui
							e.printStackTrace();
						}
					}else{
						//TODO display error
						messages.append("At max reverse");
					}
				}

				else if (command.equals("Zero Steering")){
					try {
						boolean isSet = truck.setDireciton(0);
						if(isSet){
							currentDirection = 0;
						}else{
							//TODO disp message
						}
					} catch (RemoteException e) {
						// TODO disp message
						e.printStackTrace();
					}
				}

				else if (command.equals("Zero Throttle")){
					try {
						boolean isSet = truck.setThrottle(0);
						if(isSet){
							currentThrottle = 0;
						}else{
							//TODO display message
						}
					} catch (RemoteException e) {
						// TODO check if connected and disp message
						e.printStackTrace();
					}
				}

				else{
					System.out.println("Button Failed");
				}
			} 
		};

		leftSteer.addActionListener(aListener);
		rightSteer.addActionListener(aListener);
		faster.addActionListener(aListener);
		slower.addActionListener(aListener);
		zeroSteer.addActionListener(aListener);
		zeroThrottle.addActionListener(aListener);

		return Control;
	}

	@Override
	public InetAddress getIpAddress() throws RemoteException {
		InetAddress answer = null;
		try {
			answer = InetAddress.getLocalHost();
		} catch (UnknownHostException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}		
		return answer;
	}

	@Override
	public boolean isConnected() throws RemoteException {
		return true;
	}
}